/**
 * @file    drv_lin.c
 * @author  yhy
 * @brief   芯必达IM94x系列芯片, lin抽象层
 * @version 1.03
 * @date    2025-07-15
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-15     yhy          the first version V1.01
 * 2025-07-17     yhy          新增lin主机模块 V1.01
 * 2025-07-18     yhy          主机新增帧间隔 V1.02
 * 2025-08-22     yhy          新增lin主机模式下超时检测 V1.03
 *
 */
#include "drv_lin.h"

#include "gpio_drv.h"
#include "lin_drv.h"

#define LIN_BAUD_RATE           19200U /* LIN波特率: 19200kpbs */
#define LIN_HW_INSTANCE_MAXSIZE 3U     /* LIN硬件实例最大数量 */
#define LIN_MASTER_RESP_TIMEOUT 2U     /* LIN主机响应次数 */

/**
 * @brief LIN引脚路由
 *
 */
typedef struct
{
    GPIO_Type     *tx_port; /*!< LIN TX端口  */
    uint32_t       tx_pin;  /*!< LIN TX引脚  */
    GPIO_Type     *rx_port; /*!< LIN RX端口  */
    uint32_t       rx_pin;  /*!< LIN RX引脚  */
    gpio_pin_mux_t mux;     /*!< LIN引脚复用 */
} snf_lin_pin_route_t;

/**
 * @brief LIN硬件实例管理
 *
 */
typedef struct
{
    bool        initialized; /*!< 是否初始化 */
    lin_state_t state;       /*!< LIN状态 */
    UART_Type  *linX_addr;   /*!< LIN实例地址 */
} snf_lin_hw_manager_t;

static result_e                snf_drv_lin_param_verify(const snf_lin_config_t *lin_config);
static result_e                snf_drv_lin_gpio_config(const snf_lin_pin_route_t *pin_route);
static result_e                snf_drv_lin_config(const snf_lin_config_t *lin_config);
static void                    snf_drv_lin_callback(uint32_t instance, lin_event_id_t event, void *param);
static uint32_t                snf_drv_lin_get_hw_instance(snf_lin_instance_e instance);
static result_e                snf_drv_lin_master_resp_timeout_dec(void);
static void                    snf_drv_lin_set_master_resp_timeout(uint16_t timeout);
static snf_lin_transfer_mode_e snf_drv_lin_get_transfer_mode(void);

static lin_config_t lin_base_config = {
    .autobaud        = true,
    .baudRate        = LIN_BAUD_RATE,
    .nodeMode        = LIN_MODE_SLAVE,
    .classicPID      = NULL,
    .numOfClassicPID = 0U,
    .callback        = NULL,
    .callbackParam   = NULL,
};

/* LIN pin查找表 */
static const snf_lin_pin_route_t lin_pin_route_table[LIN_INSTANCE_MAX] = {
    [LIN_INSTANCE_UART0_0] = { GPIOC, 3U, GPIOC, 2U, GPIO_PIN_MUX_FUN4 },
    [LIN_INSTANCE_UART0_1] = { GPIOB, 1U, GPIOB, 0U, GPIO_PIN_MUX_FUN4 },
    [LIN_INSTANCE_UART0_2] = { GPIOC, 9U, GPIOC, 8U, GPIO_PIN_MUX_FUN5 },
    [LIN_INSTANCE_UART1_0] = { GPIOA, 1U, GPIOA, 0U, GPIO_PIN_MUX_FUN3 },
    [LIN_INSTANCE_UART1_1] = { GPIOE, 5U, GPIOE, 4U, GPIO_PIN_MUX_FUN4 },
    [LIN_INSTANCE_UART1_2] = { GPIOA, 3U, GPIOA, 2U, GPIO_PIN_MUX_FUN5 },
    [LIN_INSTANCE_UART1_3] = { GPIOA, 11U, GPIOA, 10U, GPIO_PIN_MUX_FUN6 },
    [LIN_INSTANCE_UART2_0] = { GPIOD, 7U, GPIOD, 6U, GPIO_PIN_MUX_FUN3 },
    [LIN_INSTANCE_UART2_1] = { GPIOD, 1U, GPIOD, 0U, GPIO_PIN_MUX_FUN4 },
    [LIN_INSTANCE_UART2_2] = { GPIOC, 9U, GPIOC, 8U, GPIO_PIN_MUX_FUN4 },
    [LIN_INSTANCE_UART2_3] = { GPIOC, 7U, GPIOC, 6U, GPIO_PIN_MUX_FUN5 },
};

/* LIN 硬件实例管理 */
static snf_lin_hw_manager_t lin_hw_manager_list[LIN_HW_INSTANCE_MAXSIZE] = {
    { false, { 0 }, UART0 },
    { false, { 0 }, UART1 },
    { false, { 0 }, UART2 },
};

/* LIN 硬件实例地址查找表 */
static UART_Type *lin_hw_addr_table[LIN_HW_INSTANCE_MAXSIZE] = { UART0, UART1, UART2 };

/* LIN调度列表 */
static snf_lin_scheduler_t lin_scheduler_list[LIN_SCHEDULER_MAXIZE];

/* LIN调度器数量 */
static uint8_t lin_scheduler_count = 0;

/* lin配置信息 */
static snf_lin_config_t lin_config_info;

/**
 * @brief 初始化LIN, 波特率为19200kbps
 *
 * @param lin_config    LIN配置结构体
 * @return result_e     初始化结果, RESULT_STATUS_OK表示初始化成功, 其他值表示初始化失败
 */
result_e snf_drv_lin_init(const snf_lin_config_t *lin_config)
{
    result_e result = snf_drv_lin_param_verify(lin_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    snf_lin_pin_route_t pin_route = lin_pin_route_table[lin_config->instance];

    result = snf_drv_lin_gpio_config(&pin_route);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    result = snf_drv_lin_config(lin_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    uint32_t hw_instance = snf_drv_lin_get_hw_instance(lin_config->instance);

    lin_hw_manager_list[hw_instance].linX_addr   = lin_hw_addr_table[hw_instance];
    lin_hw_manager_list[hw_instance].initialized = true;

    memcpy(&lin_config_info, lin_config, sizeof(snf_lin_config_t));

    return RESULT_STATUS_OK;
}

/**
 * @brief 注册LIN调度列表
 *
 * @param scheduler_list        LIN调度列表
 * @param list_size             调度列表大小
 * @return result_e             注册结果, RESULT_STATUS_OK表示注册成功, 其他值表示注册失败
 */
result_e snf_drv_lin_register_scheduler(const snf_lin_scheduler_t *scheduler_list, uint8_t list_size)
{
    if (!list_size) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    memcpy(lin_scheduler_list, scheduler_list, sizeof(snf_lin_scheduler_t) * list_size);
    lin_scheduler_count = list_size;

    return RESULT_STATUS_OK;
}

/**
 * @brief LIN数据传输, 作为主机时放在调度器中发送帧头
 *
 * @return result_e 返回结果, RESULT_STATUS_OK表示发送成功, 其他值表示发送失败
 */
result_e snf_drv_lin_transfer(void)
{
    if (lin_base_config.nodeMode == LIN_MODE_SLAVE) {
        return RESULT_STATUS_ERROR;
    }

    uint32_t hw_instance = snf_drv_lin_get_hw_instance(lin_config_info.instance);

    /* 从机响应超时处理 */
    if (snf_drv_lin_master_resp_timeout_dec() == RESULT_STATUS_ERROR) {
        LIN_TimeoutService(hw_instance);
    }

    static uint8_t lin_frame_idx = 0;
    if (lin_frame_idx >= lin_scheduler_count) {
        lin_frame_idx = 0;
    }

    errcode_t ret = LIN_MasterSendHeader(hw_instance, lin_scheduler_list[lin_frame_idx].id);
    if (ret != ERR_SUCCESS) {
        return RESULT_STATUS_LIN_TRANSFER_ERROR;
    }

    ++lin_frame_idx;

    return RESULT_STATUS_OK;
}

/**
 * @brief 获取lin传输模式
 *
 * @return snf_lin_transfer_mode_e 传输模式
 */
static snf_lin_transfer_mode_e snf_drv_lin_get_transfer_mode(void) { return lin_config_info.transfer_mode; }

/**
 * @brief 设置lin主机发送从机响应超时时间
 *
 * @param timeout 超时时间, 单位为以snf_drv_lin_transfer调度周期为准
 */
static void snf_drv_lin_set_master_resp_timeout(uint16_t timeout)
{
    lin_config_info.resp_timeout = timeout;
}

/**
 * @brief lin主机发送从机响应超时时间减1
 *
 * @return result_e 操作状态, 成功返回RESULT_STATUS_OK，反之为失败
 */
static result_e snf_drv_lin_master_resp_timeout_dec(void)
{
    if (lin_config_info.resp_timeout) {
        --lin_config_info.resp_timeout;
        return RESULT_STATUS_OK;
    }

    return RESULT_STATUS_ERROR;
}

/**
 * @brief 初始化LIN相关配置
 *
 * @param lin_config    LIN配置结构体
 * @return result_e     返回结果, RESULT_STATUS_OK表示初始化成功, 其他值表示初始化失败
 */
static result_e snf_drv_lin_config(const snf_lin_config_t *lin_config)
{
    uint32_t hw_instance = snf_drv_lin_get_hw_instance(lin_config->instance);

    /* 设置LIN模式 */
    lin_base_config.nodeMode = (lin_mode_t)lin_config->transfer_mode;

    errcode_t ret = LIN_Init(hw_instance, &(lin_hw_manager_list[hw_instance].state), &lin_base_config);
    if (ret != ERR_SUCCESS) {
        return RESULT_STATUS_LIN_INIT_ERROR;
    }

    LIN_InstallCallback(hw_instance, snf_drv_lin_callback, NULL);

    return RESULT_STATUS_OK;
}

/**
 * @brief 通过LIN实例，获取LIN硬件实例
 *
 * @param instance      LIN实例
 * @return uint32_t     LIN硬件实例
 */
static uint32_t snf_drv_lin_get_hw_instance(snf_lin_instance_e instance)
{
    static const uint32_t lin_hw_instance_map[LIN_INSTANCE_MAX] = {
        [LIN_INSTANCE_UART0_0] = 0U, [LIN_INSTANCE_UART0_1] = 0U, [LIN_INSTANCE_UART0_2] = 0U,
        [LIN_INSTANCE_UART1_0] = 1U, [LIN_INSTANCE_UART1_1] = 1U, [LIN_INSTANCE_UART1_2] = 1U,
        [LIN_INSTANCE_UART1_3] = 1U, [LIN_INSTANCE_UART2_0] = 2U, [LIN_INSTANCE_UART2_1] = 2U,
        [LIN_INSTANCE_UART2_2] = 2U, [LIN_INSTANCE_UART2_3] = 2U,
    };

    return lin_hw_instance_map[(uint32_t)instance];
}

/**
 * @brief 初始化LIN GPIO
 *
 * @param pin_route     pin脚路由
 * @return result_e     返回结果, RESULT_STATUS_OK表示初始化成功, 其他值表示初始化失败
 */
static result_e snf_drv_lin_gpio_config(const snf_lin_pin_route_t *pin_route)
{
    if (!pin_route) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    GPIO_SetPinFunc(pin_route->tx_port, pin_route->tx_pin, pin_route->mux);
    GPIO_SetPinFunc(pin_route->rx_port, pin_route->rx_pin, pin_route->mux);

    return RESULT_STATUS_OK;
}

/**
 * @brief 校验LIN配置参数
 *
 * @param lin_config    LIN配置结构体
 * @return result_e     校验结果, RESULT_STATUS_OK表示校验成功, 其他值表示校验失败
 */
static result_e snf_drv_lin_param_verify(const snf_lin_config_t *lin_config)
{
    if (!lin_config) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (lin_config->instance >= LIN_INSTANCE_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (lin_config->transfer_mode >= LIN_TRANSFER_MODE_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief LIN回调函数
 *
 * @param instance  LIN实例
 * @param event     LIN事件
 * @param param     LIN事件参数
 */
static void snf_drv_lin_callback(uint32_t instance, lin_event_id_t event, void *param)
{
    lin_state_t *lin_state_param = (lin_state_t *)param;
    uint8_t      i               = 0; /* 调度表索引 */

    switch (event) {
    case LIN_PID_OK:
        /* 接收到头帧 */
        if (lin_state_param->nodeState == LIN_NODE_STATE_RECV_HDR_COMPLETED) {
            for (i = 0; i < lin_scheduler_count; ++i) {
                /* LIN调度表中找接收到的对应的id */
                if (lin_scheduler_list[i].id == lin_state_param->id) {
                    if (lin_scheduler_list[i].transfer_type == LIN_TRANSFER_TYPE_SEND) {
                        (void)LIN_SendFrameData(instance, lin_scheduler_list[i].data,
                                                lin_scheduler_list[i].data_len);
                    }
                    else {
                        (void)LIN_ReceiveFrameData(instance, lin_scheduler_list[i].data,
                                                   lin_scheduler_list[i].data_len);
                    }
                    break;
                }
            }
        }
        break;

    case LIN_TX_COMPLETED:
        if (lin_scheduler_list[i].callback) {
            lin_scheduler_list[i].callback();
        }
        break;

    case LIN_RX_COMPLETED:
        /* 主机模式下，从机响应超时时间设置 */
        if (snf_drv_lin_get_transfer_mode() == LIN_TRANSFER_MODE_MASTER) {
            snf_drv_lin_set_master_resp_timeout(LIN_MASTER_RESP_TIMEOUT);
        }
        break;
    }
}
